接着看看实现的效果图
在这篇文章中主要采用ViewDragHelper
这个类,这个是系统提供的一个处理view
拖动的一个类。具体请查看相关资料,在这就不多说。
先来解析实现的思路,view
的移动采用ViewDragHelper
即可,如果下方是一般的View
的话就差不多了,但是如果是ListView
或者RecyclerView
之类的话主要处理一个事件拦截的逻辑。首先要清楚ListView
或者RecyclerView
在处理事件的时候调用了getParent().requestDisallowInterceptTouchEvent(true);
请求父布局不拦截事件,所以当拦截的时候不能让ListView
或者RecyclerView
接受到MOVE
事件。逻辑很简单,就是当下面的ListView
或者RecyclerView
到顶部 并且是下拉的时候就需要使用ViewDragHelper
来响应拖动,如果上面的菜单是打开状态的话那么也需要响应,这时候就需要拦截MOVE
事件来处理拖动。逻辑就是这么简单,但是细节的东西有很多,不能马虎并且熟悉相关的api
。
接下来开始撸码
这里我选择继承FrameLayout
,在初始化的时候创建ViewDragHelper
,资源加载完毕了得到需要拖动的mDragView
,在测量之后获取到最大拖动的距离,也就是上方菜单的高度,当手指抬起的时候判断是需要关闭还是打开
1 | class VerticalDragListView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr: Int = 0) |
在这需要注意一点,当手指松开判断打开或者关闭菜单需要调用invalidate()
并且重写computeScroll()
函数来响应。
如果下方的view
不是ListView
或者RecyclerView
之类的话,到这就可以了,但是实际开发中,下方一般是这种,所以就需要按照上面说的处理事件拦截
1 | private var mDownY: Float = 0.0f |
这里需要注意,如果不在ACTION_DOWN
的时候调用mViewDragHelper.processTouchEvent(ev)
的话,那么ViewDragHelper
将会报错,将不会触发拖动事件
从字面意思都可以看出需要一个完整的事件,所以需要在ACTION_DOWN
的时候调用ViewDragHelper.processTouchEvent(ev)
在一步步的分析之下,这个效果就慢慢的完成了。有了新需求的时候,在动手应该理清思路,然后想好使用相关的api
,处理一些手势可以使用OnGestureListener
,处理拖动可以使用ViewDragHelper
,这些都是系统封装好的辅助类,应该要合理的利用这些辅助类。相信如果不使用这些辅助类也可以写出这些效果,但是那样的话也会浪费大量的事件和精力,而且很容易出错。
v1.5.2